package com.siemens.industrial.security;

import com.siemens.industrial.model.IUser;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * Created by weig on 10/20/16.
 */
public class MultiTenantSecurityFilter implements Filter {

    private String partnerUrlPattern;
    private String adminUrlPattern = "/admin/**";

    private String adminLoginUrl = "/admin/login";
    private String partnerLoginUrl = "/partner/{tenant}/login";

    private List<String> ignoreUrlPattern = new ArrayList<>();

    private static final AntPathMatcher matcher = new AntPathMatcher();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        try {
            InputStream stream = this.getClass().getResourceAsStream("/multi-tenant-auth-config.properties");
            Properties properties = new Properties();
            properties.load(stream);

            partnerLoginUrl = properties.getProperty("partnerLoginUrl");
            adminLoginUrl = properties.getProperty("adminLoginUrl");

            partnerUrlPattern = properties.getProperty("partnerUrlPattern");
            adminUrlPattern = properties.getProperty("adminUrlPattern");

            String ignoreUrls = properties.getProperty("ignoreUrls");

            if (ignoreUrls != null) {
                String[] urls = ignoreUrls.split(";");
                for (String s : urls) {
                    if (!s.trim().equals(""))
                        ignoreUrlPattern.add(s);
                }
            }
        } catch (Exception e) {
            throw new BeanCreationException("Multi-Tenant Configuration file load failed");
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;

        if (!isUrlIgnored(req)) {
            String tenant = getTenant(req);

            IUser user = getSessionUser(req.getSession());

            if (!isUserLoggedInTenant(tenant, user)) {
                rejectConnection(tenant, (HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
                return;
            }
        }

        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println();
    }

    @Override
    public void destroy() {

    }

    private void rejectConnection(String tenant, HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.getSession().setAttribute("siemense.login.backurl", request.getRequestURL().toString());

//        if (!request.getHeaders("x-requested-with").hasMoreElements()){
//            response.sendRedirect(getLoginUrl(tenant));
//            return;
//        }
        if (request.getHeaders("x-requested-with").hasMoreElements() && request.getHeaders("x-requested-with").nextElement().equalsIgnoreCase("XMLHttpRequest")) {
//        if (request.getContentType() != null && request.getContentType().equals("application/json")) {
            ServletOutputStream out = response.getOutputStream();
            String data = "{\"code\": 403, \"message\": \"Unauthorized\"}";
            response.setStatus(403);
            out.write(data.getBytes());
        } else {
            response.sendRedirect(getLoginUrl(tenant));
        }
    }

    private boolean isUrlIgnored(HttpServletRequest req) {
        for (String s : ignoreUrlPattern) {
            if (matcher.match(s, req.getServletPath()))
                return true;
        }

        return false;
    }

    private IUser getSessionUser(HttpSession session) {
        if (session == null)
            return null;

        return (IUser) session.getAttribute("siemens.multitenant.login.user");
    }

    private boolean isUserLoggedInTenant(String tenant, IUser user) {
        if (user == null)
            return false;

        if (tenant == null) {
            return user.getTenant() == null;
        } else {
            return tenant.equals(user.getTenant());
        }
    }

    private String getLoginUrl(String tenant) {
        if (tenant == null)
            return adminLoginUrl;
        else
            return partnerLoginUrl.replace("{tenant}", tenant);
    }

    private String getTenant(HttpServletRequest request) {
        if (matcher.match(partnerUrlPattern, request.getServletPath())) {
            Map<String, String> params = matcher.extractUriTemplateVariables(partnerUrlPattern, request.getServletPath());

            if (params.containsKey("tenant"))
                return params.get("tenant");
        }

        return null;
    }
}
